using Microsoft.Practices.RecipeFramework;
using System.IO;
using System.Security.AccessControl;
using System.Security.Permissions;
using System;
using System.Security;
using Microsoft.Win32;
using System.Xml;
using System.ComponentModel;

namespace SPALM.SharePointSoftwareFactory.Installer
{
    /// <summary>
    /// Installer class for the guidance package.
    /// </summary>
    [System.ComponentModel.ToolboxItem(false)]
    [RunInstaller(true)]
    public class InstallerClass : ManifestInstaller
    {
        private string vspackageGuid = "";

        public InstallerClass()
            : base()
        {
            
        }

        public override void Install(System.Collections.IDictionary stateSaver)
        {
            Console.WriteLine("Updating registry. This can take several minutes. Please wait.");
            base.Install(stateSaver);
        }

        public override void Commit(System.Collections.IDictionary savedState)
        {
            Console.WriteLine("Updating registry. This can take several minutes. Please wait.");
            base.Commit(savedState);
        }

        public override void Rollback(System.Collections.IDictionary savedState)
        {
            base.Rollback(savedState);
        } 

        protected override void OnAfterUninstall(System.Collections.IDictionary savedState)
        {
            Console.WriteLine("Updating registry. This can take several minutes. Please wait.");

            base.OnAfterUninstall(savedState);

            vspackageGuid = this.GetPackageGuid();
            Context.LogMessage("SPSF Info: GetPackageGuid returned " + vspackageGuid);

            try
            {
                UnregisterAssemblyBindingLocation();
            }
            catch (Exception)
            {
            }

            try
            {
                string packageGuid = GetPackageGuid();
                VSTemplatesRegister.Unregister(packageGuid);
            }
            catch (Exception)
            {
            }
        }

        protected override void OnCommitted(System.Collections.IDictionary savedState)
        {
            base.OnCommitted(savedState);

            vspackageGuid = this.GetPackageGuid();
            Context.LogMessage("SPSF Info: GetPackageGuid returned " + vspackageGuid);

            try
            {
                string configuration = this.Context.Parameters["configuration"];

                //get current installation directory of package
                FileInfo fInfo = new FileInfo(configuration);
                string templatesDir = fInfo.DirectoryName + "\\Templates";

                try
                {
                    string DirectoryName = templatesDir;

                    // Add the access control entry to the directory.
                    AddDirectorySecurity(DirectoryName, @"Everyone", FileSystemRights.Modify, AccessControlType.Allow);

                }
                catch (Exception e)
                {
                    Context.LogMessage("SPSF Exception 1000: " + e.ToString());
                }

                try
                {
                    RegisterVSTemplates();
                }
                catch (Exception ex3)
                {
                    Context.LogMessage("SPSF Exception 1003: " + ex3.ToString());
                }

                try
                {
                    RegisterAssemblyBindingLocation();
                }
                catch (Exception ex3)
                {
                    Context.LogMessage("SPSF Exception 1003: " + ex3.ToString());
                }
            }
            catch (Exception ex4)
            {
                Context.LogMessage("SPSF Exception 2000: " + ex4.ToString());
            }
        }

        private void RegisterAssemblyBindingLocation()
        {
            //register the installation folder for assembly search path to find sharepointbridge.dll
            RegistryKey visualStudioKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\9.0\", true);

            RegistryKey startupKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\9.0\BindingPaths\", true);
            if (startupKey == null)
            {
                startupKey = visualStudioKey.CreateSubKey("BindingPaths");
            }

            RegistryKey packageKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\9.0\BindingPaths\" + vspackageGuid, true);
            if (packageKey == null)
            {
                RegistryKey assemblysearchpath = startupKey.CreateSubKey(vspackageGuid);
                assemblysearchpath.SetValue(GetInstallDir(), "");
            }
        }

        private void UnregisterAssemblyBindingLocation()
        {            
            RegistryKey startupKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\9.0\BindingPaths\", true);
            RegistryKey packageKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\9.0\BindingPaths\" + vspackageGuid, true);
            if (packageKey != null)
            {
                startupKey.DeleteSubKey(vspackageGuid);
            }

        }

        private string GetInstallDir()
        {
            string configuration = this.Context.Parameters["configuration"];
            FileInfo fInfo = new FileInfo(configuration);
            return fInfo.DirectoryName;
        }

        private void RegisterVSTemplates()
        {
            string packageGuid = "";
            string packageName = "";
            string templatesDir = "";

            try
            {
                string configuration = this.Context.Parameters["configuration"];

                //get current installation directory of package
                FileInfo fInfo = new FileInfo(configuration);
                templatesDir = fInfo.DirectoryName + "\\Templates\\Items.Cache";

                //get package parameters
                XmlDocument manifest = new XmlDocument();
                manifest.Load(configuration);

                XmlNamespaceManager context = new XmlNamespaceManager(manifest.NameTable);
                context.AddNamespace("gax", "http://schemas.microsoft.com/pag/gax-core");
                XmlNode coreChild = manifest.SelectSingleNode("/gax:GuidancePackage", context);
                if (coreChild != null)
                {
                    packageName = coreChild.Attributes["Caption"].Value;
                    packageGuid = coreChild.Attributes["Guid"].Value;
                    if (!packageGuid.StartsWith("{"))
                    {
                        packageGuid = "{" + packageGuid + "}";
                    }
                }

                VSTemplatesRegister.Register(packageGuid, templatesDir, packageName);


            }
            catch (Exception ex)
            {
                Context.LogMessage("SPSF Exception 4000: " + ex.ToString());
            }
        }        

        private string GetPackageGuid()
        {
            try
            {
                string configuration = this.Context.Parameters["configuration"];
                string packageGuid = "";

                //get package parameters
                XmlDocument manifest = new XmlDocument();
                manifest.Load(configuration);

                XmlNamespaceManager context = new XmlNamespaceManager(manifest.NameTable);
                context.AddNamespace("gax", "http://schemas.microsoft.com/pag/gax-core");
                XmlNode coreChild = manifest.SelectSingleNode("/gax:GuidancePackage", context);
                if (coreChild != null)
                {
                    packageGuid = coreChild.Attributes["Guid"].Value;
                    if (!packageGuid.StartsWith("{"))
                    {
                        packageGuid = "{" + packageGuid + "}";
                    }
                }
                return packageGuid;                
            }
            catch (Exception ex)
            {
                Context.LogMessage("SPSF Exception 3001: " + ex.ToString());
                return "";
            }
        }


        // Adds an ACL entry on the specified directory for the specified account.
        public void AddDirectorySecurity(string FileName, string Account, FileSystemRights Rights, AccessControlType ControlType)
        {
            // Create a new DirectoryInfo object.
            DirectoryInfo dInfo = new DirectoryInfo(FileName);

            // Get a DirectorySecurity object that represents the 
            // current security settings.
            DirectorySecurity dSecurity = dInfo.GetAccessControl();

            // Add the FileSystemAccessRule to the security settings. 
            dSecurity.AddAccessRule(new FileSystemAccessRule(Account, Rights, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, ControlType));

            // Set the new access settings.
            dInfo.SetAccessControl(dSecurity);

        }
    }
}